/**
 *    Copyright (C) 2009 Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_REFLECTION_VALUE_HPP
#define _CUBEFS_CORE_API_REFLECTION_VALUE_HPP


#include <cubefs/core/api/reflection/type.hpp>
#include <cubefs/api/tools/version.hpp>
#include <cubefs/api/reflection/value.hpp>



#define CUBEFS_SOURCE "cubefs/core/api/reflection/value.hpp:" CUBEFS_AT

namespace cubefs { namespace api {

template <typename Interface>
class ValueImplT: public TypedImplT<Interface> {
	typedef ValueImplT<Interface> 	Me;
	typedef TypedImplT<Interface>	Base;

public:
	ValueImplT(): managed_(false) {}
	virtual ~ValueImplT() throw() {}


	virtual bool managed() const {
		return managed_;
	}

	virtual void SetManaged(bool managed0) {
		managed_ = managed0;
	}

	virtual void set(const void* value)  {
		throw CubefsException(CUBEFS_SOURCE, "Operation is not supported for this type of value");
	}

	virtual void get(void* value) const  {
		throw CubefsException(CUBEFS_SOURCE, "Operation is not supported for this type of value");
	}

	virtual void Set(const Value* value) {
		throw CubefsException(CUBEFS_SOURCE, "Operation is not supported for this type of value");
	}

	virtual bool IsEquals(const Value* val) const {
		return false;
	}

    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
    }

    static void InitOperations() {
    }

    CUBEFS_DECLARE_REFLECTION;
private:
    bool managed_;
};

template <typename Interface>
Type* ValueImplT<Interface>::type_ 					= NULL;

typedef ValueImplT<Value> 								ValueImpl;


template <typename T, typename Interface>
class TypedValueImplT: public ValueImplT<Interface> {
	typedef TypedValueImplT<T, Interface> 	Me;
	typedef ValueImplT<Interface>			Base;

protected:
	T value_;
public:

	TypedValueImplT(const T& value): value_(value) {}
	TypedValueImplT() {};

	virtual ~TypedValueImplT() throw() {}

	virtual const T& value() const {
		return value_;
	}

	virtual T& value() {
		return value_;
	}

	virtual const T& GetValue() const {
		return value_;
	}

	virtual void SetValue(const T& value) {
		value_ = value;
	}

	virtual void Set(const Value* value) {
		if (value != NULL)
		{
			if (value->type() == type())
			{
				const Me* value0 = static_cast<const Me*>(value);
				SetValue(value0->GetValue());
			}
			else {
				throw TypeCastException(CUBEFS_SOURCE, "Invalid argument type. It must be the same.", value->type(), type());
			}
		}
		else {
			throw NullPointerException(CUBEFS_SOURCE, "Argument must not be null");
		}
	}

	virtual void set(const void* value)  {
		value_ = *(const T*)value;
	}

	virtual void get(void* value) const  {
		*((T*)value) = value_;
	}

	virtual bool IsEquals(const Value* val) const {
		if (val != NULL && val->IsInstance(Interface::MyType()))
		{
			const Interface* v0 = static_cast<const Interface*>(val);
			return value_ == v0->GetValue();
		}
		else {
			return 0;
		}
	}

    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Value::MyType());
    }

    static void InitOperations()
    {
    	AbstractType* type = static_cast<AbstractType*>(Me::MyType());

    	type->AddOperation(new BasicOperation<T (Me::*)(), const T& (Me::*)() const>(type, "GetValue", &Me::GetValue));
    	type->AddOperation(new BasicOperation<void (Me::*)(T), void (Me::*)(const T&)>(type, "SetValue", "value", &Me::SetValue));
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename T, typename Interface>
Type* TypedValueImplT<T, Interface>::type_ 					= NULL;



template <typename T, typename Interface>
class TypedValueImplT<const T, Interface>: public ValueImplT<Interface> {
	typedef TypedValueImplT<const T, Interface> 	Me;
	typedef ValueImplT<Interface>					Base;

	T value_;
public:

	TypedValueImplT(const T& value): value_(value) {}
	TypedValueImplT() {}

	virtual ~TypedValueImplT() throw() {}

	virtual const T& value() const {
		return value_;
	}

	virtual const T& GetValue() const {
		return value_;
	}

	virtual void SetValue(const T& value) {
	}

	virtual void get(void* value) const  {
		*((T*)value) = value_;
	}

	virtual bool IsEquals(const Value* val) const {
		if (val != NULL && val->IsInstance(Interface::MyType()))
		{
			Interface* v0 = static_cast<Interface*>(val);
			return value_ == v0->GetValue();
		}
		else {
			return 0;
		}
	}

    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Value::MyType());
    }

    static void InitOperations()
    {
    	AbstractType* type = static_cast<AbstractType*>(Me::MyType());
    	type->AddOperation(new BasicOperation<T (Me::*)(), const T& (Me::*)() const>(type, "GetValue", &Me::GetValue));
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename T, typename Interface>
Type* TypedValueImplT<const T, Interface>::type_ 					= NULL;



template <typename T, typename Interface>
class TypedValueImplT<const T&, Interface>: public ValueImplT<Interface> {
	typedef TypedValueImplT<const T&, Interface> 	Me;
	typedef ValueImplT<Interface>					Base;

	const T& value_;
public:

	TypedValueImplT(const T& value): value_(value) {}
	TypedValueImplT() {}

	virtual ~TypedValueImplT() throw() {}

	virtual const T& value() const {
		return value_;
	}

	virtual const T& GetValue() const {
		return value_;
	}

	virtual void SetValue(const T& value) {
	}

	virtual void get(void* value) const  {
		*((T*)value) = value_;
	}

	virtual bool IsEquals(const Value* val) const {
		if (val != NULL && val->IsInstance(Interface::MyType()))
		{
			const Interface* v0 = static_cast<const Interface*>(val);
			return value_ == v0->GetValue();
		}
		else {
			return 0;
		}
	}

    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Value::MyType());
    }

    static void InitOperations()
    {
    	AbstractType* type = static_cast<AbstractType*>(Me::MyType());
    	type->AddOperation(new BasicOperation<T (Me::*)(), const T& (Me::*)() const>(type, "GetValue", &Me::GetValue));
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename T, typename Interface>
Type* TypedValueImplT<const T&, Interface>::type_ 					= NULL;


template <typename T, typename Interface>
class TypedValueImplT<T&, Interface>: public ValueImplT<Interface> {
	typedef TypedValueImplT<T&, Interface> 	Me;
	typedef ValueImplT<Interface>			Base;

	const T& value_;
public:

	TypedValueImplT(const T& value): value_(value) {}
	TypedValueImplT() {}

	virtual ~TypedValueImplT() throw() {}

	virtual const T& value() const {
		return value_;
	}

	virtual const T& GetValue() const {
		return value_;
	}

	virtual void SetValue(const T& value) {
		value_ = value;
	}

	virtual void Set(const Value* value) {
		if (value != NULL)
		{
			if (value->type() == type())
			{
				const Me* value0 = static_cast<const Me*>(value);
				SetValue(value0->GetValue());
			}
			else {
				throw TypeCastException(CUBEFS_SOURCE, "Invalid argument type. It must be the same.", value->type(), type());
			}
		}
		else {
			throw NullPointerException(CUBEFS_SOURCE, "Argument must not be null");
		}
	}

	virtual void get(void* value) const  {
		*((T*)value) = value_;
	}

	virtual bool IsEquals(const Value* val) const {
		if (val != NULL && val->IsInstance(Interface::MyType()))
		{
			const Interface* v0 = static_cast<const Interface*>(val);
			return value_ == v0->GetValue();
		}
		else {
			return false;
		}
	}

    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Value::MyType());
    }

    static void InitOperations()
    {
    	AbstractType* type = static_cast<AbstractType*>(Me::MyType());
    	type->AddOperation(new BasicOperation<T (Me::*)(), const T& (Me::*)() const>(type, "GetValue", &Me::GetValue));
    	type->AddOperation(new BasicOperation<void (Me::*)(T), void (Me::*)(const T&)>(type, "SetValue", "value", &Me::SetValue));
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename T, typename Interface>
Type* TypedValueImplT<T&, Interface>::type_ 					= NULL;



template <typename T>
class TypedValueImpl: public TypedValueImplT<T, TypedValue<T> > {
	typedef TypedValueImplT<T, TypedValue<T> > Base;
public:
	TypedValueImpl(const T& value): Base(value) {}
	TypedValueImpl(): Base() {}

	virtual ~TypedValueImpl() throw() {}
};




template <typename Interface>
class VoidValueImplT: public ValueImplT<Interface> {
	typedef VoidValueImplT<Interface> 	Me;
	typedef ValueImplT<Interface>		Base;

public:

	VoidValueImplT() {}
	virtual ~VoidValueImplT() throw() {}


    static void InitType()
    {
        type_ = new AbstractType(TypeNameFactory<Interface>::name(), Value::MyType());
    }

    static void InitOperations()
    {}

    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* VoidValueImplT<Interface>::type_ 					= NULL;
typedef VoidValueImplT<VoidValue>						VoidValueImpl;




#define CUBEFS_DECLARE_VALUE_TYPE_FACTORY(TypeName)		\
template <>												\
struct TypeFactory<TypeName> {							\
    static Type* type() {								\
        return TypedValue<TypeName>::MyType();			\
    }													\
}

CUBEFS_DECLARE_VALUE_TYPE_FACTORY(bool);
CUBEFS_DECLARE_VALUE_TYPE_FACTORY(StringRef);
CUBEFS_DECLARE_VALUE_TYPE_FACTORY(String);
CUBEFS_DECLARE_VALUE_TYPE_FACTORY(void*);
CUBEFS_DECLARE_VALUE_TYPE_FACTORY(const void*);
CUBEFS_DECLARE_VALUE_TYPE_FACTORY(Version);




template <typename Type_, typename T>
struct TypedWrapperFactoryBase {
    typedef Type_ Type;

    static Type_* create(const T& value) {
        return new Type(value);
    }
};


template <typename T>
struct TypedWrapperFactory: public TypedWrapperFactoryBase<TypedValueImpl<T>, T> {};

template <>
struct TypedWrapperFactory<bool> {
    typedef TypedValueImpl<bool> Type;

    static TypedValue<bool>* create(const bool& value) {
        if (value) {
            return TYPED_TRUE;
        }
        else {
            return TYPED_FALSE;
        }
    }
};

template <typename T> struct TypedValueHelper;


template <typename T>
struct TypedValueHelper<TypedNumber<T> > {

    template <typename Value>
    static void set(Typed *number, const Value& value) {
        TypedNumber<T> *n = TypedCast<TypedNumber<T> >(number);
        n->SetValue(value);
    }

    template <typename Value>
    static Value get(Typed *number) {
        TypedNumber<T> *n = TypedCast<TypedNumber<T> >(number);
        return n->GetValue();
    }
};

template <typename T>
struct TypedValueHelper<TypedValue<T> > {

    template <typename Value>
    static void set(Typed *number, const Value& value) {
        TypedValue<T> *n = TypedCast<TypedValue<T> >(number);
        n->setValue(*(T*)value);
    }

    template <typename Value>
    static Value get(Typed *number) {
        TypedValue<T> *n = TypedCast<TypedValue<T> >(number);
        return n->getValue();
    }
};



}}

#undef CUBEFS_SOURCE
#endif
